home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / xboard21.lha / xboard-2.1.pl11 / parser.l < prev    next >
Text File  |  1993-06-14  |  39KB  |  1,410 lines

  1. %a 5000
  2. %o 5000
  3. %e 1500
  4. %k 2000
  5. %p 4000
  6. %{
  7. /*
  8.  * parser.l -- lex parser of algebraic chess moves for XBoard
  9.  *
  10.  * Original author:  Chris Sears
  11.  * Enhancements (Version 2.0):  Tim Mann
  12.  *
  13.  * XBoard borrows its colors, icon and piece bitmaps from XChess
  14.  * which was written and is copyrighted by Wayne Christopher.
  15.  *
  16.  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
  17.  * Enhancements Copyright 1992 Free Software Foundation, Inc.
  18.  *
  19.  * The following terms apply to Digital Equipment Corporation's copyright
  20.  * interest in XBoard:
  21.  * ------------------------------------------------------------------------
  22.  * All Rights Reserved
  23.  *
  24.  * Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted,
  26.  * provided that the above copyright notice appear in all copies and that
  27.  * both that copyright notice and this permission notice appear in
  28.  * supporting documentation, and that the name of Digital not be
  29.  * used in advertising or publicity pertaining to distribution of the
  30.  * software without specific, written prior permission.
  31.  *
  32.  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  33.  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  34.  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  35.  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  36.  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  37.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  38.  * SOFTWARE.
  39.  * ------------------------------------------------------------------------
  40.  *
  41.  * The following terms apply to the enhanced version of XBoard distributed
  42.  * by the Free Software Foundation:
  43.  * ------------------------------------------------------------------------
  44.  * This file is part of XBOARD.
  45.  *
  46.  * XBOARD is distributed in the hope that it will be useful, but WITHOUT ANY
  47.  * WARRANTY.  No author or distributor accepts responsibility to anyone for
  48.  * the consequences of using it or for whether it serves any particular
  49.  * purpose or works at all, unless he says so in writing.  Refer to the XBOARD
  50.  * General Public License for full details.
  51.  *
  52.  * Everyone is granted permission to copy, modify and redistribute XBOARD, but
  53.  * only under the conditions described in the XBOARD General Public License. A
  54.  * copy of this license is supposed to have been given to you along with
  55.  * XBOARD so you can know your rights and responsibilities.  It should be in a
  56.  * file named COPYING.  Among other things, the copyright notice and this
  57.  * notice must be preserved on all copies.
  58.  * ------------------------------------------------------------------------
  59.  *
  60.  * This parser handles all forms of promotion.
  61.  * The parser resolves ambiguous moves by searching and check-testing.
  62.  * It also parses comments of the form [anything] or (anything).
  63.  */
  64. #include "xboard.h"
  65. #include <ctype.h>
  66. #include <string.h>
  67.  
  68. #define False 0
  69. #define True 1
  70. #define NO_CONSTRAINT    -1
  71. #undef YYLMAX
  72. #define YYLMAX            2048
  73. #define UNPUT_BUF_SIZE        YYLMAX
  74. #undef input
  75. #undef output
  76. #undef unput
  77.  
  78. #undef WHITE_ON_MOVE
  79. #define WHITE_ON_MOVE        ((int) ((yyboardindex % 2) == 0))
  80.  
  81. extern Board    boards[MAX_MOVES];
  82. int        yyboardindex;
  83. extern int      xboardDebug;
  84. extern FILE    *gameFileFP;
  85. char        currentMoveString[YYLMAX];
  86. char        unputBuffer[UNPUT_BUF_SIZE];
  87. int        unputCount = 0;
  88.  
  89. static int RookSearch P((int *rank, int *file, ChessSquare piece,
  90.              int whiteOnMove, Board b,
  91.              int canmove, int rconstraint, int fconstraint));
  92. static int BishopSearch P((int *rank, int *file, ChessSquare piece,
  93.                int whiteOnMove, Board b,
  94.                int canmove, int rconstraint, int fconstraint));
  95. static int KnightSearch P((int *rank, int *file, ChessSquare piece,
  96.                int whiteOnMove, Board b,
  97.                int canmove, int rconstraint, int fconstraint));
  98. static int KingSearch P((int *rank, int *file, ChessSquare piece,
  99.              int whiteOnMove, Board b,
  100.              int canmove, int rconstraint, int fconstraint));
  101. static int QueenSearch P((int *rank, int *file, ChessSquare piece,
  102.               int whiteOnMove, Board b,
  103.               int canmove, int rconstraint, int fconstraint));
  104. static int CheckTest P((int whiteOnMove, Board board,
  105.             int rf, int ff, int rt, int ft));
  106. ChessMove LegalityTest P((int whiteOnMove, Board board,
  107.               int rf, int ff, int rt, int ft, int promoChar));
  108. int yywrap P((void));
  109. static int input P((void));
  110. static void output P((int ch));
  111. static void unput P((int ch));
  112. extern void CopyBoard P((Board to, Board from));
  113.  
  114. %}
  115. %%
  116.  
  117. \([0-9]+:[0-9][0-9]\) {
  118.     /* elapsed time indication, e.g. (0:12) */ 
  119.     return (int) ElapsedTime;
  120. }
  121.  
  122. "[--"[^\]]*"--]" {
  123.     /* position diagram enclosed in [-- --] */
  124.     return (int) PositionDiagram;
  125. }
  126.  
  127. \[[^\]]*\]    {                    /* anything in [] */
  128.     return (int) Comment; 
  129. }
  130.  
  131. \([^()]*(\([^()]*\))+[^()]*\)  {           /* nested () */
  132.     return (int) Comment; 
  133. }
  134.  
  135. \([^)][^)]+\)   {                 /* >=2 chars in () */
  136.     return (int) Comment; 
  137. }       
  138.  
  139. [RrBbNnQqKkPp][/]?[a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQq]\)?)? {
  140.     /*
  141.      * Fully-qualified algebraic move, possibly with promotion
  142.      */
  143.     int skip1 = 0, skip2 = 0;
  144.     ChessSquare piece;
  145.     ChessMove result;
  146.     
  147.     /*
  148.      * remove the / 
  149.      */
  150.     if (yytext[1] == '/') skip1 = 1;
  151.     
  152.     /*
  153.      * remove the [xX:-] 
  154.      */
  155.     if ((yytext[3+skip1] == 'x') || (yytext[3+skip1] == 'X') ||
  156.     (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1;
  157.     
  158.     currentMoveString[0] = yytext[1+skip1];
  159.     currentMoveString[1] = yytext[2+skip1];
  160.     currentMoveString[2] = yytext[3+skip1+skip2];
  161.     currentMoveString[3] = yytext[4+skip1+skip2];
  162.     currentMoveString[4] = NULLCHAR;
  163.     
  164.     if (yyleng-skip1-skip2 > 5) {
  165.     if (yytext[yyleng-1] == ')') {
  166.         currentMoveString[4] = ToLower(yytext[yyleng-2]);
  167.     } else {
  168.         currentMoveString[4] = ToLower(yytext[yyleng-1]);
  169.     }
  170.     currentMoveString[5] = NULLCHAR;
  171.     }
  172.  
  173.     piece = boards[yyboardindex]
  174.       [currentMoveString[1] - '1'][currentMoveString[0] - 'a'];
  175.     if (ToLower(yytext[0]) != ToLower(PieceToChar(piece)))
  176.       return (int) BadMove;
  177.  
  178.     result = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  179.               currentMoveString[1] - '1',
  180.               currentMoveString[0] - 'a',
  181.               currentMoveString[3] - '1',
  182.               currentMoveString[2] - 'a',
  183.               currentMoveString[4]);
  184.  
  185.     if (currentMoveString[4] == NULLCHAR &&
  186.     (result == WhitePromotionQueen || result == BlackPromotionQueen)) {
  187.     currentMoveString[4] = 'q';
  188.     currentMoveString[5] = NULLCHAR;
  189.     }
  190.  
  191.     return (int) result;
  192. }
  193.  
  194. [a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQq]\)?)?    {
  195.     /*
  196.      * Simple algebraic move, possibly with promotion
  197.      */
  198.     int skip = 0;
  199.     ChessMove result;
  200.  
  201.     /*
  202.      * remove the [xX:-] 
  203.      */
  204.     if ((yytext[2] == 'x') || (yytext[2] == 'X') ||
  205.     (yytext[2] == '-') || (yytext[2] == ':')) skip = 1;
  206.  
  207.     currentMoveString[0] = yytext[0];
  208.     currentMoveString[1] = yytext[1];
  209.     currentMoveString[2] = yytext[2+skip];
  210.     currentMoveString[3] = yytext[3+skip];
  211.     currentMoveString[4] = NULLCHAR;
  212.  
  213.     if (yyleng-skip > 4) {
  214.     if (yytext[yyleng-1] == ')') {
  215.         currentMoveString[4] = ToLower(yytext[yyleng-2]);
  216.     } else {
  217.         currentMoveString[4] = ToLower(yytext[yyleng-1]);
  218.     }
  219.     currentMoveString[5] = NULLCHAR;
  220.     }
  221.  
  222.     result = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  223.               currentMoveString[1] - '1',
  224.               currentMoveString[0] - 'a',
  225.               currentMoveString[3] - '1',
  226.               currentMoveString[2] - 'a',
  227.               currentMoveString[4]);
  228.  
  229.     if (currentMoveString[4] == NULLCHAR &&
  230.     (result == WhitePromotionQueen || result == BlackPromotionQueen)) {
  231.     currentMoveString[4] = 'q';
  232.     currentMoveString[5] = NULLCHAR;
  233.     }
  234.  
  235.     return (int) result;
  236. }
  237.  
  238. [a-h][1-8](=?\(?[RrBbNnQq]\)?)?    {
  239.     /*
  240.      * Pawn move, possibly with promotion
  241.      */
  242.     int rank, file;
  243.     ChessMove result;
  244.  
  245.     currentMoveString[0] = yytext[0];
  246.     currentMoveString[1] = yytext[1];
  247.     currentMoveString[2] = yytext[0];
  248.     currentMoveString[3] = yytext[1];
  249.     currentMoveString[4] = NULLCHAR;
  250.  
  251.     rank = yytext[1] - '1';
  252.     file = yytext[0] - 'a';
  253.  
  254.     if (WHITE_ON_MOVE) {
  255.     if (rank <= 0) return (int) BadMove;
  256.     if (rank == 3 && boards[yyboardindex][2][file] == EmptySquare)
  257.       currentMoveString[1] -= 2;
  258.     else
  259.       currentMoveString[1]--;
  260.     } else {
  261.     if (rank >= 7) return (int) BadMove;
  262.     if (rank == 4 && boards[yyboardindex][5][file] == EmptySquare)
  263.       currentMoveString[1] += 2;
  264.     else
  265.       currentMoveString[1]++;
  266.     }
  267.  
  268.     if (yyleng > 2) {
  269.     if (yytext[yyleng-1] == ')') {
  270.         currentMoveString[4] = ToLower(yytext[yyleng-2]);
  271.     } else {
  272.         currentMoveString[4] = ToLower(yytext[yyleng-1]);
  273.     }
  274.     currentMoveString[5] = NULLCHAR;
  275.     }
  276.  
  277.     result = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  278.               currentMoveString[1] - '1',
  279.               currentMoveString[0] - 'a',
  280.               currentMoveString[3] - '1',
  281.               currentMoveString[2] - 'a',
  282.               currentMoveString[4]);
  283.  
  284.     if (currentMoveString[4] == NULLCHAR &&
  285.     (result == WhitePromotionQueen || result == BlackPromotionQueen)) {
  286.     currentMoveString[4] = 'q';
  287.     currentMoveString[5] = NULLCHAR;
  288.     }
  289.  
  290.     return (int) result;
  291. }
  292.  
  293.  
  294. (ab|bc|cd|de|ef|fg|gh|hg|gf|fe|ed|dc|cb|ba|([a-h][xX:-][a-h]))(=?\(?[RrBbNnQq]\)?)? {
  295.     /*
  296.      * Pawn capture, possibly with promotion, possibly ambiguous
  297.      */
  298.     int i, file0, file1, skip = 0, found = 0;
  299.     ChessMove result, r;
  300.  
  301.     /*
  302.      * remove the [xX:-]
  303.      */
  304.     if ((yytext[1] == 'x') || (yytext[1] == 'X')
  305.     || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1;
  306.  
  307.     file0 = yytext[0] - 'a';
  308.     file1 = yytext[1+skip] - 'a';
  309.  
  310.     currentMoveString[0] = yytext[0];
  311.     currentMoveString[2] = yytext[1+skip];
  312.     if (yyleng-skip > 2) {
  313.     if (yytext[yyleng-1] == ')')
  314.       currentMoveString[4] = ToLower(yytext[yyleng-2]);
  315.     else
  316.       currentMoveString[4] = ToLower(yytext[yyleng-1]);
  317.     currentMoveString[5] = NULLCHAR;
  318.     } else {
  319.     currentMoveString[4] = NULLCHAR;
  320.     }
  321.  
  322.     result = BadMove;
  323.     if (WHITE_ON_MOVE) {
  324.     for (i = 1; i < BOARD_SIZE - 1; i++) {
  325.         if (boards[yyboardindex][i][file0] == WhitePawn) {
  326.         r = LegalityTest(True, boards[yyboardindex],
  327.                       i, file0, i + 1, file1,
  328.                       currentMoveString[4]);
  329.         if (r != BadMove) {
  330.             found++;
  331.             if (found > 1) return (int) AmbiguousMove;
  332.             currentMoveString[1] = '1' + i;
  333.             currentMoveString[3] = '1' + i + 1;
  334.             result = r;
  335.         }
  336.         }
  337.     }
  338.     } else {
  339.     for (i = 1; i < BOARD_SIZE - 1; i++) {
  340.         if (boards[yyboardindex][i][file0] == BlackPawn) {
  341.         r = LegalityTest(False, boards[yyboardindex],
  342.                       i, file0, i - 1, file1,
  343.                       currentMoveString[4]);
  344.         if (r != BadMove) {
  345.             found++;
  346.             if (found > 1) return (int) AmbiguousMove;
  347.             currentMoveString[1] = '1' + i;
  348.             currentMoveString[3] = '1' + i - 1;
  349.             result = r;
  350.         }
  351.         }
  352.     }
  353.     }
  354.  
  355.     if (currentMoveString[4] == NULLCHAR &&
  356.     (result == WhitePromotionQueen || result == BlackPromotionQueen)) {
  357.     currentMoveString[4] = 'q';
  358.     currentMoveString[5] = NULLCHAR;
  359.     }
  360.  
  361.     return (int) result;
  362. }
  363.  
  364. [a-h][xX:]?[a-h][1-8](=?\(?[RrBbNnQq]\)?)?    {
  365.     /*
  366.      * unambiguously abbreviated Pawn capture, possibly with promotion
  367.      */
  368.     int skip = 0;
  369.     ChessMove result;
  370.  
  371.     /*
  372.      * remove the [xX:-]
  373.      */
  374.     if ((yytext[1] == 'x') || (yytext[1] == 'X')
  375.     || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1;
  376.  
  377.     currentMoveString[0] = yytext[0];
  378.     currentMoveString[2] = yytext[1+skip];
  379.     currentMoveString[3] = yytext[2+skip];
  380.     if (WHITE_ON_MOVE) {
  381.     if (yytext[2+skip] == '1') return (int) BadMove;
  382.     currentMoveString[1] = yytext[2+skip] - 1;
  383.     } else {
  384.     if (yytext[2+skip] == '8') return (int) BadMove;
  385.     currentMoveString[1] = yytext[2+skip] + 1;
  386.     }
  387.     if (yyleng-skip > 3) {
  388.     if (yytext[yyleng-1] == ')')
  389.       currentMoveString[4] = ToLower(yytext[yyleng-2]);
  390.     else
  391.       currentMoveString[4] = ToLower(yytext[yyleng-1]);
  392.     currentMoveString[5] = NULLCHAR;
  393.     } else {
  394.     currentMoveString[4] = NULLCHAR;
  395.     }
  396.  
  397.     result = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  398.               currentMoveString[1] - '1',
  399.               currentMoveString[0] - 'a',
  400.               currentMoveString[3] - '1',
  401.               currentMoveString[2] - 'a',
  402.               currentMoveString[4]);
  403.  
  404.     if (currentMoveString[4] == NULLCHAR &&
  405.     (result == WhitePromotionQueen || result == BlackPromotionQueen)) {
  406.     currentMoveString[4] = 'q';
  407.     currentMoveString[5] = NULLCHAR;
  408.     }
  409.  
  410.     if (result != BadMove) return (int) result;
  411.  
  412.     /* Special case: improperly written en passant capture */
  413.     if (WHITE_ON_MOVE) {
  414.     if (currentMoveString[3] == '5') {
  415.         currentMoveString[1] = '5';
  416.         currentMoveString[3] = '6';
  417.     } else {
  418.         return (int) BadMove;
  419.     }
  420.     } else {
  421.     if (currentMoveString[3] == '4') {
  422.         currentMoveString[1] = '4';
  423.         currentMoveString[3] = '3';
  424.     } else {
  425.         return (int) BadMove;
  426.     }
  427.     }
  428.  
  429.     result = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  430.               currentMoveString[1] - '1',
  431.               currentMoveString[0] - 'a',
  432.               currentMoveString[3] - '1',
  433.               currentMoveString[2] - 'a',
  434.               currentMoveString[4]);
  435.  
  436.     if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant)
  437.       return (int) result;
  438.     else
  439.       return (int) BadMove;
  440. }
  441.  
  442. [RrBbNnQqKk][xX:-]?[a-h][1-8]  {
  443.     /*
  444.      * piece move, possibly ambiguous
  445.      */
  446.     int rank, file, found;
  447.     ChessMove r, result = NormalMove;
  448.     ChessSquare piece;
  449.  
  450.     if ((yytext[1] == 'x') || (yytext[1] == 'X')
  451.     || (yytext[1] == ':') || (yytext[1] == '-')) {
  452.     currentMoveString[2] = yytext[2];
  453.     currentMoveString[3] = yytext[3];
  454.     } else {
  455.     currentMoveString[2] = yytext[1];
  456.     currentMoveString[3] = yytext[2];
  457.     }
  458.     currentMoveString[4] = NULLCHAR;
  459.  
  460.     rank = currentMoveString[3] - '1';
  461.     file = currentMoveString[2] - 'a';
  462.  
  463.     switch (yytext[0]) {
  464.       case 'R': case 'r':
  465.     piece = WHITE_ON_MOVE ? WhiteRook : BlackRook;
  466.     found = RookSearch(&rank, &file, piece,
  467.                WHITE_ON_MOVE, boards[yyboardindex],
  468.                True, NO_CONSTRAINT, NO_CONSTRAINT);
  469.     break;
  470.       case 'B': case 'b':
  471.     piece = WHITE_ON_MOVE ? WhiteBishop : BlackBishop;
  472.     found = BishopSearch(&rank, &file, piece,
  473.                  WHITE_ON_MOVE, boards[yyboardindex],
  474.                  True, NO_CONSTRAINT, NO_CONSTRAINT);
  475.     break;
  476.       case 'N': case 'n':
  477.     piece = WHITE_ON_MOVE ? WhiteKnight : BlackKnight;
  478.     found = KnightSearch(&rank, &file, piece,
  479.                  WHITE_ON_MOVE, boards[yyboardindex],
  480.                  True, NO_CONSTRAINT, NO_CONSTRAINT);
  481.     break;
  482.       case 'Q': case 'q':
  483.     piece = WHITE_ON_MOVE ? WhiteQueen : BlackQueen;
  484.     found = QueenSearch(&rank, &file, piece,
  485.                 WHITE_ON_MOVE, boards[yyboardindex],
  486.                 True, NO_CONSTRAINT, NO_CONSTRAINT);
  487.     break;
  488.       case 'K': case 'k':
  489.     piece = WHITE_ON_MOVE ? WhiteKing : BlackKing;
  490.     found = KingSearch(&rank, &file, piece,
  491.                WHITE_ON_MOVE, boards[yyboardindex],
  492.                True, NO_CONSTRAINT, NO_CONSTRAINT);
  493.     if (found == 0 && (rank == 0 || rank == 7) &&
  494.         (file == 2 || file == 6)) {
  495.         /* Try castling */
  496.         if (boards[yyboardindex][rank][4] == piece) {
  497.             r = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  498.                  rank, 4, rank, file, NULLCHAR);
  499.         if (r != BadMove) {
  500.             found++;
  501.             result = r;
  502.             file = 4;
  503.         }
  504.         }
  505.     }
  506.     break;
  507.     }
  508.  
  509.     switch (found) {
  510.       case 1: 
  511.     currentMoveString[0] = file + 'a';
  512.     currentMoveString[1] = rank + '1';
  513.     return (int) result;
  514.       case 0:
  515.     return (int) BadMove;
  516.       default:
  517.     return (int) AmbiguousMove;
  518.     }
  519. }
  520.  
  521. [RrBbNnQqKk][a-h1-8][xX:-]?[a-h][1-8]    {
  522.     /*
  523.      * piece move with rank or file disambiguator
  524.      */
  525.     int rc, fc, rank, file, found;
  526.     ChessMove r, result = NormalMove;
  527.     ChessSquare piece;
  528.  
  529.     if ((yytext[2] == 'x') || (yytext[2] == 'X')
  530.     || (yytext[2] == ':') || (yytext[2] == '-')) {
  531.     currentMoveString[2] = yytext[3];
  532.     currentMoveString[3] = yytext[4];
  533.     rank = yytext[4] - '1'; file = yytext[3] - 'a';
  534.     } else {
  535.     currentMoveString[2] = yytext[2];
  536.     currentMoveString[3] = yytext[3];
  537.     rank = yytext[3] - '1'; file = yytext[2] - 'a';
  538.     }
  539.  
  540.     currentMoveString[4] = NULLCHAR;
  541.  
  542.     if (isalpha(yytext[1])) {
  543.     fc = yytext[1] - 'a';
  544.     rc = NO_CONSTRAINT;
  545.     } else {
  546.     fc = NO_CONSTRAINT;
  547.     rc = yytext[1] - '1';
  548.     }
  549.  
  550.     switch (yytext[0]) {
  551.       case 'R': case 'r':
  552.     piece = WHITE_ON_MOVE ? WhiteRook : BlackRook;
  553.     found = RookSearch(&rank, &file, piece, WHITE_ON_MOVE,
  554.                boards[yyboardindex], True, rc, fc);
  555.     break;
  556.       case 'B': case 'b':
  557.     piece = WHITE_ON_MOVE ? WhiteBishop : BlackBishop;
  558.     found = BishopSearch(&rank, &file, piece, WHITE_ON_MOVE,
  559.                  boards[yyboardindex], True, rc, fc);
  560.     break;
  561.       case 'N': case 'n':
  562.     piece = WHITE_ON_MOVE ? WhiteKnight : BlackKnight;
  563.     found = KnightSearch(&rank, &file, piece, WHITE_ON_MOVE,
  564.                  boards[yyboardindex], True, rc, fc);
  565.     break;
  566.       case 'Q': case 'q':
  567.     piece = WHITE_ON_MOVE ? WhiteQueen : BlackQueen;
  568.     found = QueenSearch(&rank, &file, piece, WHITE_ON_MOVE,
  569.                 boards[yyboardindex], True, rc, fc);
  570.     break;
  571.       case 'K': case 'k':
  572.     piece = WHITE_ON_MOVE ? WhiteKing : BlackKing;
  573.     found = KingSearch(&rank, &file, piece, WHITE_ON_MOVE,
  574.                boards[yyboardindex], True, rc, fc);
  575.     if (found == 0 && (rank == 0 || rank == 7) &&
  576.         (file == 2 || file == 6)) {
  577.         /* Try castling */
  578.         if ((rc == NO_CONSTRAINT || rc == rank) &&
  579.         (fc == NO_CONSTRAINT || fc == 4) &&
  580.         (boards[yyboardindex][rank][4] == piece)) {
  581.             r = LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  582.                  rank, 4, rank, file, NULLCHAR);
  583.         if (r != BadMove) {
  584.             found++;
  585.             result = r;
  586.             file = 4;
  587.         }
  588.         }
  589.     }
  590.     break;
  591.     }
  592.  
  593.     switch (found) {
  594.       case 1: 
  595.     currentMoveString[0] = file + 'a';
  596.     currentMoveString[1] = rank + '1';
  597.     return (int) result;
  598.       case 0:
  599.     return (int) BadMove;
  600.       default:
  601.     return (int) AmbiguousMove;
  602.     }
  603. }
  604.  
  605. 000|0-0-0|ooo|OOO|o-o-o|O-O-O    {
  606.     int rf, ff, rt, ft;
  607.  
  608.     if (WHITE_ON_MOVE) {
  609.     if (boards[yyboardindex][0][3] == WhiteKing) {
  610.         /* ICS wild castling */
  611.         strcpy(currentMoveString, "d1f1");
  612.         rf = 0;
  613.         ff = 3;
  614.         rt = 0;
  615.         ft = 5;
  616.     } else {
  617.         strcpy(currentMoveString, "e1c1");
  618.         rf = 0;
  619.         ff = 4;
  620.         rt = 0;
  621.         ft = 2;
  622.     }
  623.     } else{ 
  624.     if (boards[yyboardindex][7][3] == BlackKing) {
  625.         /* ICS wild castling */
  626.         strcpy(currentMoveString, "d8f8");
  627.         rf = 7;
  628.         ff = 3;
  629.         rt = 7;
  630.         ft = 5;
  631.     } else {
  632.         strcpy(currentMoveString, "e8c8");
  633.         rf = 7;
  634.         ff = 4;
  635.         rt = 7;
  636.         ft = 2;
  637.     }
  638.     }
  639.     return (int) LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  640.                   rf, ff, rt, ft, NULLCHAR);
  641. }
  642.  
  643. 00|0-0|oo|OO|o-o|O-O    {
  644.     int rf, ff, rt, ft;
  645.  
  646.     if (WHITE_ON_MOVE) {
  647.     if (boards[yyboardindex][0][3] == WhiteKing) {
  648.         /* ICS wild castling */
  649.         strcpy(currentMoveString, "d1b1");
  650.         rf = 0;
  651.         ff = 3;
  652.         rt = 0;
  653.         ft = 1;
  654.     } else {
  655.         strcpy(currentMoveString, "e1g1");
  656.         rf = 0;
  657.         ff = 4;
  658.         rt = 0;
  659.         ft = 6;
  660.     }
  661.     } else {
  662.     if (boards[yyboardindex][7][3] == BlackKing) {
  663.         /* ICS wild castling */
  664.         strcpy(currentMoveString, "d8b8");
  665.         rf = 7;
  666.         ff = 3;
  667.         rt = 7;
  668.         ft = 1;
  669.     } else {
  670.         strcpy(currentMoveString, "e8g8");
  671.         rf = 7;
  672.         ff = 4;
  673.         rt = 7;
  674.         ft = 6;
  675.     }
  676.     }
  677.     return (int) LegalityTest(WHITE_ON_MOVE, boards[yyboardindex],
  678.                   rf, ff, rt, ft, NULLCHAR);
  679. }
  680.  
  681. [Rr](esign|ESIGN)([Ss]|[Ee][Dd])?  {
  682.     if (WHITE_ON_MOVE)
  683.       return (int) BlackWins;
  684.     else
  685.       return (int) WhiteWins;
  686. }
  687.  
  688. [Ww](hite|HITE)?" "[Rr](esign|ESIGN)([Ss]|[Ee][Dd])?  {
  689.     return (int) BlackWins;
  690. }
  691.  
  692. [Bb](lack|LACK)?" "[Rr](esign|ESIGN)([Ss]|[Ee][Dd])?  {
  693.     return (int) WhiteWins;
  694. }
  695.  
  696. [Ww](hite|HITE)?" "[Aa](sserts|SSERTS)" "([aA]" ")?[Ww](in|IN)  {
  697.     return (int) WhiteWins;
  698. }
  699.  
  700. [Bb](lack|LACK)?" "[Aa](sserts|SSERTS)" "([aA]" ")?[Ww](in|IN)  {
  701.     return (int) BlackWins;
  702. }
  703.  
  704. [Ss](talemate|TALEMATE)  {
  705.     return (int) GameIsDrawn;
  706. }
  707.  
  708. ([Cc](heck|HECK))?[Mm](ate|ATE)  {
  709.     if (WHITE_ON_MOVE)
  710.       return (int) WhiteWins;
  711.     else
  712.       return (int) BlackWins;
  713. }
  714.  
  715. ([Bb](lack|LACK)?|[Ww](hite|HITE)?)" "[Oo](ffers|FFERS)" "[Dd](raw|RAW)[Nn]?  {
  716.     return (int) GameIsDrawn;
  717. }
  718.  
  719. [Dd](raw|RAW)[Nn]?(" "[Bb][Yy])?(" "[Rr](epetition|EPETITION)|" "[Aa](gree|GREE)([Dd]|(ment|MENT))?) {
  720.     return (int) GameIsDrawn;
  721. }
  722.  
  723. [Dd](raw|RAW)[Nn]?(" (".*")")?  {
  724.     return (int) GameIsDrawn;
  725. }
  726.  
  727. [Ww](hite|HITE)?(" "[Ww][IiOo][Nn][Ss]?(" "[Oo][Nn]" "[Tt](ime|IME))?(" (".*")")?|" "[Mm](ates|ATES))? { 
  728.     return (int) WhiteWins;
  729. }
  730.  
  731. [Bb](lack|LACK)?(" "[Ww][IiOo][Nn][Ss]?(" "[Oo][Nn]" "[Tt](ime|IME))?(" (".*")")?|" "[Mm](ates|ATES))? { 
  732.     return (int) BlackWins;
  733. }
  734.  
  735. [Ww](hite|HITE)?" "[Ll][Oo][Ss]([Tt]|[Es][Ss])(" "[Oo][Nn]" "[Tt](ime|IME))? { 
  736.     return (int) BlackWins;
  737. }
  738.  
  739. [Bb](lack|LACK)?" "[Ll][Oo][Ss]([Tt]|[Es][Ss])(" "[Oo][Nn]" "[Tt](ime|IME))? { 
  740.     return (int) WhiteWins;
  741. }
  742.  
  743. 1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0"    { 
  744.     return (int) WhiteWins;
  745. }
  746. 0-1|"0 - 1"|"0/1"|"0 / 1"|"0:1"|"0 : 1"    { 
  747.     return (int) BlackWins;
  748. }
  749. ("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))? {
  750.     return (int) GameIsDrawn;
  751. }
  752.  
  753. [1-9][0-9]*/[. \t\n]*[a-hNnPp]    {
  754.     /* move numbers */
  755.     /* note: above regular expression assumes game starts from
  756.        conventional opening position, so that only pawn and
  757.        knight moves are legal. */
  758.     
  759.     if ((yyleng == 1) && (yytext[0] == '1'))
  760.       return (int) StartGame;
  761. }
  762.  
  763. [Gg](nu|NU)" "?[Cc](hess|HESS).*[Gg](ame|AME) {
  764.     return (int) StartGame;
  765. }
  766.  
  767. [a-zA-Z0-9'-]+            {
  768.         /* Skip random words */
  769. }
  770.  
  771. .|"\n"                {
  772.         /* Skip everything else */
  773. }
  774.  
  775. %%
  776.  
  777.  
  778. /*
  779.     Test whether a piece of the given type attacks the square (*rank, *file)
  780.     on board b, assuming it moves as a rook.  If canmove is True, the
  781.     piece must be able to move legally to the square; otherwise we test
  782.     only if it attacks the square.  rconstraint is either NO_CONSTRAINT or
  783.     the rank the piece must start on; fconstraint is either NO_CONSTRAINT
  784.     or the file the piece must start on.  Upon return, *rank and *file
  785.     are modified to point to one of the pieces found, if any, and the
  786.     function return value is the number of pieces found.
  787. */
  788.  
  789. static int RookSearch(rank, file, piece,
  790.                       whiteOnMove, b, canmove, rconstraint, fconstraint)
  791.      int *rank, *file, whiteOnMove, canmove, rconstraint, fconstraint;
  792.      ChessSquare piece;
  793.      Board b;
  794. {
  795.     int i, r = *rank, f = *file, found = 0;
  796.     
  797.     /*
  798.      * Start from the target space and work outwards towards the piece.
  799.      * This is necessary for check testing.
  800.      */
  801.     for (i = f + 1;; i++) {
  802.     if (i >= BOARD_SIZE)
  803.       break;
  804.     if ((b[r][i] != EmptySquare) && (b[r][i] != piece))
  805.       break;
  806.     if (fconstraint != NO_CONSTRAINT && i != fconstraint)
  807.       continue;
  808.     if (rconstraint != NO_CONSTRAINT && (r != rconstraint))
  809.       break;
  810.     if (canmove)
  811.       if (CheckTest(whiteOnMove, b, r, i, r, f))
  812.         continue;
  813.     if (b[r][i] == piece) {
  814.         *file = i;
  815.         found++;
  816.         break;
  817.     }
  818.     }
  819.     
  820.     for (i = f - 1;; i--) {
  821.     if (i < 0)
  822.       break;
  823.     if ((b[r][i] != EmptySquare) && (b[r][i] != piece))
  824.       break;
  825.     if (fconstraint != NO_CONSTRAINT && (i != fconstraint))
  826.       continue;
  827.     if (rconstraint != NO_CONSTRAINT && (r != rconstraint))
  828.       break;
  829.     if (canmove)
  830.       if (CheckTest(whiteOnMove, b, r, i, r, f))
  831.         continue;
  832.     if (b[r][i] == piece) {
  833.         *file = i;
  834.         found++;
  835.         break;
  836.     }
  837.     }
  838.     
  839.     for (i = r + 1;; i++) {
  840.     if (i >= BOARD_SIZE)
  841.       break;
  842.     if ((b[i][f] != EmptySquare) && (b[i][f] != piece))
  843.       break;
  844.     if (fconstraint != NO_CONSTRAINT && (f != fconstraint))
  845.       break;
  846.     if (rconstraint != NO_CONSTRAINT && (i != rconstraint))
  847.       continue;
  848.     if (canmove)
  849.       if (CheckTest(whiteOnMove, b, i, f, r, f))
  850.         continue;
  851.     if (b[i][f] == piece) {
  852.         *rank = i;
  853.         found++;
  854.         break;
  855.     }
  856.     }
  857.     
  858.     for (i = r - 1;; i--) {
  859.     if (i < 0)
  860.       break;
  861.     if ((b[i][f] != EmptySquare) && (b[i][f] != piece))
  862.       break;
  863.     if (fconstraint != NO_CONSTRAINT && (f != fconstraint))
  864.       break;
  865.     if (rconstraint != NO_CONSTRAINT && (i != rconstraint))
  866.       continue;
  867.     if (canmove)
  868.       if (CheckTest(whiteOnMove, b, i, f, r, f))
  869.         continue;
  870.     if (b[i][f] == piece) {
  871.         *rank = i;
  872.         found++;
  873.         break;
  874.     }
  875.     }
  876.     
  877.     return found;
  878. }
  879.  
  880. /*
  881.     Test whether a piece of the given type attacks the square (*rank, *file)
  882.     on board b, assuming it moves as a bishop.  If canmove is True, the
  883.     piece must be able to move legally to the square; otherwise we test
  884.     only if it attacks the square.  rconstraint is either NO_CONSTRAINT or
  885.     the rank the piece must start on; fconstraint is either NO_CONSTRAINT
  886.     or the file the piece must start on.  Upon return, *rank and *file
  887.     are modified to point to one of the pieces found, if any, and the
  888.     function return value is the number of pieces found.
  889. */
  890.  
  891. static int BishopSearch(rank, file, piece, whiteOnMove, b,
  892.             canmove, rconstraint, fconstraint)
  893.      int *rank, *file, whiteOnMove, canmove, rconstraint, fconstraint;
  894.      ChessSquare piece;
  895.      Board b;
  896. {
  897.     int i, j, ii, jj, r = *rank, f = *file, found = 0;
  898.     
  899.     for (ii = -1; ii <= 1; ii += 2)
  900.       for (jj = -1; jj <= 1; jj += 2) {
  901.       /*
  902.        * Start from the target space and work outwards towards the piece.
  903.        * This is necessary for check testing.
  904.        */
  905.       for (i = r + ii, j = f + jj;; i += ii, j += jj) {
  906.           if ((i < 0) || (i >= BOARD_SIZE) || (j < 0) || (j >= BOARD_SIZE))
  907.         break;
  908.           if ((b[i][j] != EmptySquare) && (b[i][j] != piece))
  909.         break;
  910.           if (fconstraint != NO_CONSTRAINT && (j != fconstraint))
  911.         continue;
  912.           if (rconstraint != NO_CONSTRAINT && (i != rconstraint))
  913.         continue;
  914.           if (canmove)
  915.         if (CheckTest(whiteOnMove, b, i, j, r, f)) {
  916.             continue;
  917.         }
  918.           if (b[i][j] == piece) {
  919.           *rank = i;
  920.           *file = j;
  921.           found++;
  922.           break;
  923.           }
  924.       }
  925.       }      
  926.  
  927.     return found;
  928. }
  929.  
  930. /*
  931.     Test whether a piece of the given type attacks the square (*rank, *file)
  932.     on board b, assuming it moves as a knight.  If canmove is True, the
  933.     piece must be able to move legally to the square; otherwise we test
  934.     only if it attacks the square.  rconstraint is either NO_CONSTRAINT or
  935.     the rank the piece must start on; fconstraint is either NO_CONSTRAINT
  936.     or the file the piece must start on.  Upon return, *rank and *file
  937.     are modified to point to one of the pieces found, if any, and the
  938.     function return value is the number of pieces found.
  939. */
  940.  
  941. static int KnightSearch(rank, file, piece,
  942.             whiteOnMove, b, canmove, rconstraint, fconstraint)
  943.      int *rank, *file, whiteOnMove, canmove, rconstraint, fconstraint;
  944.      ChessSquare piece;
  945.      Board b;
  946. {
  947.     int i, j, s, rr, ff, r = *rank, f = *file, found = 0;
  948.  
  949.     for (i = -1; i <= 1; i += 2)
  950.       for (j = -1; j <= 1; j += 2)
  951.     for (s = 1; s <= 2; s++) {
  952.         rr = r + i*s;
  953.         ff = f + j*(3-s);
  954.         if (rr < 0 || rr > 7 || ff < 0 || ff > 7) continue;
  955.         if (rconstraint != NO_CONSTRAINT && rr != rconstraint) continue;
  956.         if (fconstraint != NO_CONSTRAINT && ff != fconstraint) continue;
  957.         if (b[rr][ff] == piece &&
  958.         !(canmove && CheckTest(whiteOnMove, b, rr, ff, r, f))) {
  959.         *rank = rr;
  960.         *file = ff;
  961.         found++;
  962.         }
  963.     }
  964.     return found;
  965. }
  966.  
  967.  
  968. /*
  969.     Test whether a piece of the given type attacks the square (*rank, *file)
  970.     on board b, assuming it moves as a king.  If canmove is True, the
  971.     piece must be able to move legally to the square; otherwise we test
  972.     only if it attacks the square.  rconstraint is either NO_CONSTRAINT or
  973.     the rank the piece must start on; fconstraint is either NO_CONSTRAINT
  974.     or the file the piece must start on.  Upon return, *rank and *file
  975.     are modified to point to one of the pieces found, if any, and the
  976.     function return value is the number of pieces found.
  977. */
  978.  
  979. static int KingSearch(rank, file, piece,
  980.               whiteOnMove, b, canmove, rconstraint, fconstraint)
  981.      int *rank, *file, whiteOnMove, canmove, rconstraint, fconstraint;
  982.      ChessSquare piece;
  983.      Board b;
  984. {
  985.     int i, j, rr, ff, r = *rank, f = *file, found = 0;
  986.  
  987.     for (i = -1; i <= 1; i++)
  988.       for (j = -1; j <= 1; j++) {
  989.       if (i == 0 && j == 0) continue;
  990.       rr = r + i;
  991.       ff = f + j;
  992.       if (rr < 0 || rr > 7 || ff < 0 || ff > 7) continue;
  993.       if (rconstraint != NO_CONSTRAINT && rr != rconstraint) continue;
  994.       if (fconstraint != NO_CONSTRAINT && ff != fconstraint) continue;
  995.       if (b[rr][ff] == piece &&
  996.           !(canmove && CheckTest(whiteOnMove, b, rr, ff, r, f))) {
  997.           *rank = rr;
  998.           *file = ff;
  999.           found++;
  1000.       }
  1001.       }
  1002.     return found;
  1003. }
  1004.  
  1005.  
  1006. /*
  1007.     Test whether a piece of the given type attacks the square (*rank, *file)
  1008.     on board b, assuming it moves as a queen.  If canmove is True, the
  1009.     piece must be able to move legally to the square; otherwise we test
  1010.     only if it attacks the square.  rconstraint is either NO_CONSTRAINT or
  1011.     the rank the piece must start on; fconstraint is either NO_CONSTRAINT
  1012.     or the file the piece must start on.  Upon return, *rank and *file
  1013.     are modified to point to one of the pieces found, if any, and the
  1014.     function return value is the number of pieces found.
  1015. */
  1016.  
  1017. static int QueenSearch(rank, file, piece,
  1018.                whiteOnMove, b, canmove, rconstraint, fconstraint)
  1019.      int *rank, *file, whiteOnMove, canmove, rconstraint, fconstraint;
  1020.      ChessSquare piece;
  1021.      Board b;
  1022. {
  1023.     int rrook = *rank, frook = *file, nrook;
  1024.     int rbishop = *rank, fbishop = *file, nbishop;
  1025.     
  1026.     nrook = RookSearch(&rrook, &frook, piece,
  1027.                whiteOnMove, b, canmove, rconstraint, fconstraint);
  1028.     nbishop = BishopSearch(&rbishop, &fbishop, piece,
  1029.                whiteOnMove, b, canmove, rconstraint, fconstraint);
  1030.     if (nrook > 0) {
  1031.     *rank = rrook;
  1032.     *file = frook;
  1033.     } else if (nbishop > 0) {
  1034.     *rank = rbishop;
  1035.     *file = fbishop;
  1036.     }
  1037.  
  1038.     return nrook + nbishop;
  1039. }
  1040.  
  1041. /*
  1042.     Return True if moving from (rf, ff) to (rt, ft) is illegal
  1043.     because it would leave the player on move in check.
  1044. */
  1045. static int CheckTest(whiteOnMove, board, rf, ff, rt, ft)
  1046.      int whiteOnMove;
  1047.      Board board;
  1048.      int rf, ff, rt, ft;
  1049. {
  1050.     int rk, fk, rank, file;
  1051.     Board b;
  1052.     
  1053.     CopyBoard(b, board);
  1054.     b[rt][ft] = b[rf][ff];
  1055.     b[rf][ff] = EmptySquare;
  1056.     
  1057.     for (rk = 0; rk < BOARD_SIZE; rk++) {
  1058.     for (fk = 0; fk < BOARD_SIZE; fk++) {
  1059.         if (b[rk][fk] == (whiteOnMove ? WhiteKing : BlackKing)) {
  1060.         if (whiteOnMove) {
  1061.             if (rk+1 <= 7) {
  1062.             if (fk-1 >= 0 && b[rk+1][fk-1] == BlackPawn)
  1063.               return True;
  1064.             if (fk+1 <= 7 && b[rk+1][fk+1] == BlackPawn)
  1065.               return True;
  1066.             }
  1067.         } else {
  1068.             if (rk-1 >= 0) {
  1069.             if (fk-1 >= 0 && b[rk-1][fk-1] == WhitePawn)
  1070.               return True;
  1071.             if (fk+1 <= 7 && b[rk-1][fk+1] == WhitePawn)
  1072.               return True;
  1073.             }
  1074.         }
  1075.         rank = rk; file = fk;
  1076.         if (KnightSearch(&rank, &file,
  1077.                  whiteOnMove ? BlackKnight : WhiteKnight,
  1078.                  whiteOnMove, b, False,
  1079.                  NO_CONSTRAINT, NO_CONSTRAINT))
  1080.           return True;
  1081.         rank = rk; file = fk;
  1082.         if (BishopSearch(&rank, &file,
  1083.                  whiteOnMove ? BlackBishop : WhiteBishop,
  1084.                  whiteOnMove, b, False,
  1085.                  NO_CONSTRAINT, NO_CONSTRAINT))
  1086.           return True;
  1087.         rank = rk; file = fk;
  1088.         if (RookSearch(&rank, &file,
  1089.                    whiteOnMove ? BlackRook : WhiteRook,
  1090.                    whiteOnMove, b, False, 
  1091.                    NO_CONSTRAINT, NO_CONSTRAINT))
  1092.           return True;
  1093.         rank = rk; file = fk;
  1094.         if (QueenSearch(&rank, &file,
  1095.                 whiteOnMove ? BlackQueen : WhiteQueen,
  1096.                 whiteOnMove, b, False, 
  1097.                 NO_CONSTRAINT, NO_CONSTRAINT))
  1098.           return True;
  1099.         rank = rk; file = fk;
  1100.         if (KingSearch(&rank, &file,
  1101.                    whiteOnMove ? BlackKing : WhiteKing,
  1102.                    whiteOnMove, b, False,
  1103.                    NO_CONSTRAINT, NO_CONSTRAINT))
  1104.           return True;
  1105.         }
  1106.     }
  1107.     }
  1108.     
  1109.     return False;
  1110. }
  1111.  
  1112. /*
  1113.     Test whether moving from (rf, ff) to (rt, ft) and promoting
  1114.     to promoChar is legal.  If the move is not a promotion, promoChar
  1115.     must be NULLCHAR.  If the move is a promotion, and promoChar is
  1116.     NULLCHAR, we assume the promotion is to a queen.
  1117. */
  1118. ChessMove LegalityTest(whiteOnMove, board, rf, ff, rt, ft, promoChar)
  1119.      int whiteOnMove;
  1120.      Board board;
  1121.      int rf, ff, rt, ft;
  1122.      int promoChar;
  1123. {
  1124.     ChessSquare piece, dpiece;
  1125.     int rank, file, rookfile, dir;
  1126.  
  1127.     piece = board[rf][ff];
  1128.     if (whiteOnMove) {
  1129.     if ((int) piece < (int) WhitePawn || (int) piece > (int) WhiteKing)
  1130.       return BadMove;
  1131.     } else {
  1132.     if ((int) piece < (int) BlackPawn || (int) piece > (int) BlackKing)
  1133.       return BadMove;
  1134.     }
  1135.  
  1136.     switch (piece) {
  1137.       case WhitePawn:
  1138.     if (CheckTest(whiteOnMove, board, rf, ff, rt, ft)) return BadMove;
  1139.     if (ft == ff) {
  1140.         /* Non-capture */
  1141.         if (rt == rf + 1) {
  1142.         if (board[rt][ft] != EmptySquare) return BadMove;
  1143.         } else {
  1144.         if ((rf != 1) || (rt != 3) ||
  1145.             (board[rf + 1][ft] != EmptySquare) ||
  1146.             (board[rt][ft] != EmptySquare)) return BadMove;
  1147.         }
  1148.     } else {
  1149.         /* Capture */
  1150.         if ((ft != ff - 1) && (ft != ff + 1)) return BadMove;
  1151.         if (rt != rf + 1) return BadMove;
  1152.         dpiece = board[rt][ft];
  1153.         if (dpiece == EmptySquare && rf == 4 &&
  1154.         board[rf][ft] == BlackPawn &&
  1155.         board[rt + 1][ft] == EmptySquare)
  1156.           /* For now, don't check whether black just moved */
  1157.           return WhiteCapturesEnPassant;
  1158.         if ((int) dpiece < (int) BlackPawn ||
  1159.         (int) dpiece > (int) BlackKing)
  1160.           return BadMove;
  1161.     }
  1162.     switch (promoChar) {
  1163.       case NULLCHAR:
  1164.         if (rt == 7) return WhitePromotionQueen;
  1165.         return NormalMove;
  1166.       case 'n':
  1167.       case 'N':
  1168.         if (rt != 7) return BadMove;
  1169.         return WhitePromotionKnight;
  1170.       case 'b':
  1171.       case 'B':
  1172.         if (rt != 7) return BadMove;
  1173.         return WhitePromotionBishop;
  1174.       case 'r':
  1175.       case 'R':
  1176.         if (rt != 7) return BadMove;
  1177.         return WhitePromotionRook;
  1178.       case 'q':
  1179.       case 'Q':
  1180.         if (rt != 7) return BadMove;
  1181.         return WhitePromotionQueen;
  1182.       default:
  1183.         return BadMove;
  1184.     }
  1185.       case BlackPawn:
  1186.     if (CheckTest(whiteOnMove, board, rf, ff, rt, ft)) return BadMove;
  1187.     if (ft == ff) {
  1188.         /* Non-capture */
  1189.         if (rt == rf - 1) {
  1190.         if (board[rt][ft] != EmptySquare) return BadMove;
  1191.         } else {
  1192.         if ((rf != 6) || (rt != 4) ||
  1193.             (board[rf - 1][ft] != EmptySquare) ||
  1194.             (board[rt][ft] != EmptySquare)) return BadMove;
  1195.         }
  1196.     } else {
  1197.         /* Capture */
  1198.         if ((ft != ff - 1) && (ft != ff + 1)) return BadMove;
  1199.         if (rt != rf - 1) return BadMove;
  1200.         dpiece = board[rt][ft];
  1201.         if (dpiece == EmptySquare && rf == 3 &&
  1202.         board[rf][ft] == WhitePawn &&
  1203.         board[rt - 1][ft] == EmptySquare)
  1204.           /* For now, don't check whether white just moved */
  1205.           return BlackCapturesEnPassant;
  1206.         if ((int) dpiece < (int) WhitePawn ||
  1207.         (int) dpiece > (int) WhiteKing)
  1208.           return BadMove;
  1209.     }
  1210.     switch (promoChar) {
  1211.       case NULLCHAR:
  1212.         if (rt == 0) return BlackPromotionQueen;
  1213.         return NormalMove;
  1214.       case 'n':
  1215.       case 'N':
  1216.         if (rt != 0) return BadMove;
  1217.         return BlackPromotionKnight;
  1218.       case 'b':
  1219.       case 'B':
  1220.         if (rt != 0) return BadMove;
  1221.         return BlackPromotionBishop;
  1222.       case 'r':
  1223.       case 'R':
  1224.         if (rt != 0) return BadMove;
  1225.         return BlackPromotionRook;
  1226.       case 'q':
  1227.       case 'Q':
  1228.         if (rt != 0) return BadMove;
  1229.         return BlackPromotionQueen;
  1230.       default:
  1231.         return BadMove;
  1232.     }
  1233.       case WhiteKnight:
  1234.       case BlackKnight:
  1235.     rank = rt; file = ft;
  1236.     if (KnightSearch(&rank, &file, piece,
  1237.              whiteOnMove, board, True, rf, ff) != 1)
  1238.       return BadMove;
  1239.     break;
  1240.       case WhiteBishop:
  1241.       case BlackBishop:
  1242.     rank = rt; file = ft;
  1243.     if (BishopSearch(&rank, &file, piece,
  1244.              whiteOnMove, board, True, rf, ff) != 1)
  1245.       return BadMove;
  1246.     break;
  1247.       case WhiteRook:
  1248.       case BlackRook:
  1249.     rank = rt; file = ft;
  1250.     if (RookSearch(&rank, &file, piece,
  1251.                whiteOnMove, board, True, rf, ff) != 1)
  1252.       return BadMove;
  1253.     break;
  1254.       case WhiteQueen:
  1255.       case BlackQueen:
  1256.     rank = rt; file = ft;
  1257.     if (QueenSearch(&rank, &file, piece,
  1258.             whiteOnMove, board, True, rf, ff) != 1)
  1259.       return BadMove;
  1260.     break;
  1261.       case WhiteKing:
  1262.       case BlackKing:
  1263.     if ((ff == 4 && (ft == 6 || ft == 2)) ||
  1264.         (ff == 3 && (ft == 5 || ft == 1))) {
  1265.         /* Test for legal castling move
  1266.            or ICS wild castling move.
  1267.         */
  1268.         if ((rt != rf) ||
  1269.         (whiteOnMove && rf != 0) ||
  1270.         (!whiteOnMove && rf != 7))
  1271.           return BadMove;
  1272.         if (ft < ff) {
  1273.         dir = -1;
  1274.         rookfile = 0;
  1275.         } else {
  1276.         dir = 1;
  1277.         rookfile = 7;
  1278.         }
  1279.         file = ff + dir;
  1280.         while (file != rookfile) {
  1281.         if (board[rt][file] != EmptySquare) return BadMove;
  1282.         file += dir;
  1283.         }
  1284.         if (board[rt][rookfile] != (whiteOnMove ? WhiteRook : BlackRook))
  1285.           return BadMove;
  1286.         if (CheckTest(whiteOnMove, board, rf, ff, rf, ff) ||
  1287.         CheckTest(whiteOnMove, board, rf, ff, rf, ff + dir) ||
  1288.         CheckTest(whiteOnMove, board, rf, ff, rt, ft))
  1289.           return BadMove;
  1290.         /* For now, we don't check if the king or rook has moved */
  1291.         if (whiteOnMove) {
  1292.         switch (ft) {
  1293.           case 2:
  1294.             return WhiteQueenSideCastle;
  1295.           case 6:
  1296.             return WhiteKingSideCastle;
  1297.           case 1:
  1298.             return WhiteQueenSideCastleWild;
  1299.           case 5:
  1300.             return WhiteKingSideCastleWild;
  1301.         }
  1302.         } else {
  1303.         switch (ft) {
  1304.           case 2:
  1305.             return BlackQueenSideCastle;
  1306.           case 6:
  1307.             return BlackKingSideCastle;
  1308.           case 1:
  1309.             return BlackQueenSideCastleWild;
  1310.           case 5:
  1311.             return BlackKingSideCastleWild;
  1312.         }
  1313.         }
  1314.     }
  1315.     rank = rt; file = ft;
  1316.     if (KingSearch(&rank, &file, piece,
  1317.                whiteOnMove, board, True, rf, ff) != 1)
  1318.       return BadMove;
  1319.     break;
  1320.       case EmptySquare:
  1321.       default:
  1322.     return BadMove;
  1323.     }
  1324.     if (promoChar != NULLCHAR) return BadMove;
  1325.     dpiece = board[rt][ft];
  1326.     if (dpiece == EmptySquare) return NormalMove;
  1327.     if (whiteOnMove) {
  1328.     if ((int) dpiece < (int) BlackPawn || (int) dpiece > (int) BlackKing)
  1329.       return BadMove;
  1330.     } else {
  1331.     if ((int) dpiece < (int) WhitePawn || (int) dpiece > (int) WhiteKing)
  1332.       return BadMove;
  1333.     }    
  1334.     return NormalMove;
  1335. }
  1336.  
  1337.  
  1338. int yywrap()
  1339. {
  1340.     return True;
  1341. }
  1342.  
  1343. static char *StringToLex;
  1344.  
  1345. static int input()
  1346. {
  1347.     int ret;
  1348.     
  1349.     if (StringToLex != NULL) {
  1350.     ret = *StringToLex;
  1351.     if (ret == NULLCHAR)
  1352.       ret = EOF;
  1353.     else
  1354.       StringToLex++;
  1355.     } else if (unputCount > 0) {
  1356.     ret = unputBuffer[--unputCount];
  1357.     } else {
  1358.     ret = fgetc(gameFileFP);
  1359.     }    
  1360.  
  1361.     if (ret == EOF) 
  1362.       return 0;
  1363.     else
  1364.       return ret;
  1365. }
  1366.  
  1367. static void output(ch)
  1368.      int ch;
  1369. {
  1370.     fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n",
  1371.         ch, ch);
  1372. }
  1373.  
  1374. static void unput(ch)
  1375.      int ch;
  1376. {
  1377.     if (ch == 0) return;
  1378.     if (StringToLex != NULL) {
  1379.     StringToLex--;
  1380.     } else {
  1381.     if (unputCount >= UNPUT_BUF_SIZE)
  1382.       fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n",
  1383.           ch, ch);
  1384.     unputBuffer[unputCount++] = ch;
  1385.     }
  1386. }
  1387.  
  1388. void yynewfile()
  1389. {
  1390.     unputCount = 0;
  1391. }
  1392.  
  1393. /* Parse a move from the given string */
  1394. /* Return a pointer to the first unparsed character 
  1395.    in "next" if it is non-NULL */
  1396. ChessMove yylexstr(boardIndex, s, next)
  1397.      int boardIndex;
  1398.      char *s;
  1399.      char **next;
  1400. {
  1401.     ChessMove ret;
  1402.     
  1403.     StringToLex = s;
  1404.     yyboardindex = boardIndex;
  1405.     ret = (ChessMove) yylex();
  1406.     if (next != NULL) *next = StringToLex;
  1407.     StringToLex = NULL;
  1408.     return ret;
  1409. }
  1410.